/**
 * This provide data to simulate the Uniform Linear Motion.
 * In this model we assume following cases:
 * 	1. We try to release the Vehicles at the same time;
 * 	2. Each vehicle has random speed from 1 to 120 km/h according to Gaussian ("normally") distributed;
 * 	3. Every vehicle make uniform linear motion;
 */
package com.pi.model;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;

import com.pi.vo.LocationInfo;
import com.pi.vo.VehicleInfo;

/**
 * @author Coy.Qiu
 *
 */
public class UniformLinearMotionProvider implements IDataProvider {
	
	private Map<String, Integer> vehicleSpeedMap = new HashMap<String, Integer>();
	private Map<String, Integer> vehicleTypeMap = new HashMap<String, Integer>();
	DecimalFormat doubleFormat = new DecimalFormat("0.000000");

	@Override
	public Map<Calendar, List<VehicleInfo>> provideData() {
		Map<Calendar, List<VehicleInfo>> outputData = new HashMap<Calendar, List<VehicleInfo>>();
		int vehicleNum = 50;
		//Setup the time slot as 1 minute and retrieve each location record per 0.2 second
		//Then the counter should from 0 to 299
		int timePeriod = 10;
		initSpeedMap(vehicleNum);
		initType(vehicleNum);

		

		
		Calendar currentCalendar = Calendar.getInstance();
		Calendar cldr;
		List<LocationInfo> locateList = new ArrayList<LocationInfo>();
		for(int i = 0; i < timePeriod; i++)
		{
			cldr = (Calendar) currentCalendar.clone();
			cldr.add(Calendar.MILLISECOND, + 200*i);	//Add 0.2 second to the current time
			List<VehicleInfo> vehicleList = new ArrayList<VehicleInfo>();			
			//Try to generate vehicles' information
			
			for(int j = 0; j < vehicleNum; j++)
			{
				
				//Initialize a new vehicle
				VehicleInfo vehicle = new VehicleInfo();
				vehicle.setVehicleId("Vehicle-" + j);
				
				vehicle.setVehicleType(vehicleTypeMap.get(vehicle.getVehicleId()));		
				//All the vehicle start from same location
				if(i == 0)
				{
					//Initialize the start location
					LocationInfo locate = new LocationInfo();
					locate.setLongitude(116.488037);	//[22.776182,116.488037] is around our office:)
					locate.setLatitude(22.776182);
					locate.setSpeedLimit(50);
					vehicle.setCurrentLocation(locate);
					
					LocationInfo reuseLocate = new LocationInfo();
					reuseLocate.setLongitude(vehicle.getCurrentLocation().getLongitude());
					reuseLocate.setLatitude(vehicle.getCurrentLocation().getLatitude());
					reuseLocate.setSpeedLimit(vehicle.getCurrentLocation().getSpeedLimit());
					locateList.add(j, reuseLocate);

				}
				else
				{
					//Find the last location for this vehicle
					LocationInfo tmpLocate = locateList.get(j);
					vehicle.setCurrentLocation(getNextLocate(tmpLocate, vehicle.getVehicleId()));
					
					tmpLocate.setLongitude(vehicle.getCurrentLocation().getLongitude());
				}
				
				
				
				
				vehicleList.add(vehicle);
			}
			
			outputData.put(cldr, vehicleList);
		}	
		return outputData;
	}
	
	private void initSpeedMap(int vehicleNum) 
	{
		for(int j = 0; j < vehicleNum; j++)
		{
			String vehicleId = "Vehicle-" + j;
			//Get the random speed from 1 to 120 km/h according to Gaussian ("normally") distributed if not setup
			Random random = new Random();
			int speed = 0;
			while (speed < 1 || speed > 120)
			{
				speed = (int)(random.nextGaussian()*10 + 40);
			}
			System.out.println("Vehicle: " + vehicleId + " has speed: " + speed);
			vehicleSpeedMap.put(vehicleId, Integer.valueOf(speed));
		}
	}
	
	private void initType(int vehicleNum)
	{
		for(int j = 0; j < vehicleNum; j++)
		{
			String vehicleId = "Vehicle-" + j;
			Random random = new Random();
			int vehicleType = random.nextInt(3);	//The vehicle has 3 types
			
			vehicleTypeMap.put(vehicleId, Integer.valueOf(vehicleType));
			
		}
	}
	
	private LocationInfo getNextLocate(LocationInfo currentLocate, String vehicleId)
	{
		
		LocationInfo nextLocate = new LocationInfo();
		nextLocate.setSpeedLimit(currentLocate.getSpeedLimit());
		nextLocate.setLatitude(currentLocate.getLatitude());	//Keep the latitude as the same		
		// If we set the latitude as the same and just change the longitude, 
		// then 0.009738 = 1.0000416981181528 Kilometers
		// Set the time interval to 0.2 second and then can count the next longitude through the speed and time
		double nextLocateLongitude = currentLocate.getLongitude() + 0.2 * ( vehicleSpeedMap.get(vehicleId)/(60.00 * 60) ) * 0.009738;
		System.out.println("currentLocate: " + currentLocate.getLongitude() + ", nextLocateLongitude for vehicleId: " + vehicleId + " = " + nextLocateLongitude + ", remaining = " + 0.2 * ( vehicleSpeedMap.get(vehicleId)/(60.00 * 60) ) * 0.009738);
		nextLocate.setLongitude(Double.valueOf( doubleFormat.format(nextLocateLongitude)) );
		
		return nextLocate;
	}

}
